home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The 640 MEG Shareware Studio 2
/
The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO
/
clang
/
untar.zip
/
UNTAR.C
Wrap
C/C++ Source or Header
|
1992-08-16
|
8KB
|
342 lines
#include <stdio.h>
#include <io.h>
#include <ctype.h>
#include <string.h>
#include <dir.h>
const char ego[] = "UNTAR 1.0, "__DATE__ " by Ron Aaron";
const char version[] = "1.00";
int redirected = 0;
union tarheader {
char junk[512];
struct {
char name [100];
char mode [8];
char uid [8];
char gid [8];
char size [12];
char mtime[12];
char chksum[8];
char link;
char linkname[100];
} header;
} th;
long adjust(long x)
{
if (x == 0)
return 0;
x = x/512 + 1;
return x * 512;
}
static char program_name [ MAXFILE ];
void syntax(void)
{
fprintf(stderr, "\n%s %s: another fine RonWare product!", program_name, version);
fprintf(stderr, "\n");
fprintf(stderr, "\nSyntax: %s [-x] tarfile", program_name);
fprintf(stderr, "\n (stdin may be redirected, then 'program_name' isn't needed)");
fprintf(stderr, "\nThis program works on UNIX 'tar' files. Its default action is to list");
fprintf(stderr, "\nthe files contained in the archive.");
fprintf(stderr, "\n");
fprintf(stderr, "\nIf the '-x' switch is given, the files will be extracted.");
fprintf(stderr, "\n");
fprintf(stderr, "\nWhere this utility differs from MKS tar or other tar programs is that");
fprintf(stderr, "\nit knows about MS-DOS filename limitations and tells you what it's doing");
fprintf(stderr, "\nwith the file names.");
fprintf(stderr, "\n");
fprintf(stderr, "\nFor example, an entry in a tar file may have a name like:");
fprintf(stderr, "\n examples.may.92/areallongname.c");
fprintf(stderr, "\n%s converts that to:", program_name);
fprintf(stderr, "\n examples.92/areallon.c");
fprintf(stderr, "\nThis program also ignores the checksum info in the tar headers, so it may");
fprintf(stderr, "\nbe used to perform file recovery when normal tar program won't.");
exit(3);
}
void process_section( char *start, char *end )
{
char *x, *y;
int count;
/* section is of the form:
dir/ or
dir or
*/
// lowercase it, for consistency
for (x = start; x < end; x++)
*x = tolower(*x);
// get rid of sections like a.b.c
for (x=start, count = 0; x<end; x++)
{
if (*x == '.')
++count;
if (count > 1)
{
// got a weird one, let's adjust it
y = end;
while (*y != '.')
--y;
x = strchr(start,'.');
strcpy(x,y); // from last period to first period
end -= (y-x);
break;
}
}
// get rid of sections which are too long
y = strchr(start, '.');
if (!y)
{
// no extension...
if ((end-start) > 8) // name > 8 chars
strcpy(start+8, end);
}
else if (y<end)
{
if ((y-start) > 8)
{
strcpy(start + 8, y);
end -= (y-start)-8;
}
y = strchr(start, '.');
if ((end-y)>4)
{
// strcpy(y+4, end);
strcpy(y+1, end-3); // move last 3 chars
}
}
}
char *legalname(char * oldname)
{
char workbuf[100];
char *p = workbuf;
char *q;
int x;
// make copy of buffer
strncpy(workbuf, oldname, 100);
// convert illegal characters
while (p < (workbuf+100))
{
if (*p == ' ')
{
*p = '\0';
break;
}
switch (*p) {
case ':':
case '*':
case '?':
case '^':
case '=':
case '+':
case '|':
case '<':
case '>':
case ',':
*p = '_';
break;
case '\\':
*p = '/';
break;
}
++p;
}
/* convert names of form:
a.b.c
to form:
a.c
*/
p = q = workbuf;
while (*p)
{
// find next section to process
q = strchr(p, '/');
if (q == NULL)
q = p + strlen(p);
if (p == q)
{
++p;
continue;
}
process_section(p,q);
q = strchr(p, '/');
if (q == NULL)
q = p + strlen(p);
// bump p
p = (*q) ? q+1 : q;
}
return workbuf;
}
void spin()
{
fprintf(stderr, "+");
}
void makedir(char *name)
{
// create the directory 'name'
if (name[strlen(name)-1] == '/')
name[strlen(name)-1] = '\0';
if (mkdir(name) == -1)
perror(name);
}
void unarcfile(FILE *tar, char *name, long size)
{
long here;
FILE *out;
#define BUF 8*1024
static char buf[BUF];
int cnt;
here = ftell(tar);
out = fopen(name, "wb");
if (out == NULL)
{
// is the problem that there's a path prepended which we don't have?
fnsplit(name, NULL, buf, NULL, NULL);
makedir(buf);
out = fopen(name, "wb");
if (out == NULL)
{
sprintf(buf,"cannot create file [%s]", name);
perror(buf);
}
}
else
{
while (size)
{
spin();
fread(buf, BUF, 1, tar);
if (cnt == -1)
{
sprintf(buf, "error in read from [%s]", name);
perror(buf);
break;
}
cnt = (BUF > size) ? size : BUF;
fwrite(buf, 1, cnt, out);
// fputc(fgetc(tar), out);
size -= cnt;
}
fclose(out);
}
fseek(tar, here, SEEK_SET);
}
void progname( char *name, char *oname)
{
fnsplit(oname, NULL, NULL, name, NULL);
}
void main( int argc, char **argv)
{
FILE *tar;
long size, origin;
int x;
int extract = 0;
char name[100];
progname(program_name , argv[0]);
redirected = !isatty(fileno(stdout));
if ((isatty(fileno(stdin))) && (argc != 2) && (argc != 3))
syntax();
else
{
if (argv[1][0] == '-')
{
if (argv[1][1] == 'x') ++extract;
else syntax();
}
if (argc > 3) syntax;
// open file if stdin not redirected, else use stdin
if (isatty(fileno(stdin)))
tar = fopen(argv[--argc], "rb");
else
tar = stdin;
if (tar == NULL)
fprintf(stderr, "\nCannot open file %s", argv[argc]);
else
{
while (!feof(tar))
{
fread(&th, 1, sizeof(th), tar);
origin = ftell(tar);
if (th.header.name[0] == 0 || th.header.name[0] == ' ')
break;
printf("\n%s: %s, ",
(th.header.link == '5') ? "Dir " : "File",
th.header.name
);
if (redirected)
fprintf(stderr, "\n%s: %s, ",
(th.header.link == '5') ? "Dir " : "File",
th.header.name);
size = 0;
for (x=0; x<12; x++)
{
if (th.header.size[x] != ' ' && th.header.size[x] != '\0')
{
size *= 8;
size += th.header.size[x] - '0';
}
}
printf(" (%ld)", size);
strcpy(name, legalname(th.header.name));
printf(" [%s]", name);
if (redirected)
{
fprintf(stderr," (%ld)", size);
strcpy(name, legalname(th.header.name));
fprintf(stderr, " [%s]", name);
}
if (extract)
{
if (th.header.link == '5') // directory
makedir(name);
else
unarcfile(tar, name, size);
}
fseek(tar, adjust(size) + origin, SEEK_SET);
}
if (isatty(fileno(stdin)))
fclose(tar);
}
}
}